package bot.module.th.shc;

import static util.poker.texas.BetInt.*;
import static util.poker.texas.PositionInt.*;
import util.DebugOut;
import game.model.Card;

/**
 * This abstract class offers the body for every particular startingHandChart </br>
 * 
 * @author Witthold/Korol
 */
public abstract class StartingHandChart implements IF_StartingHandChart {

	/** fields needed for creating the tables */
	/** 1:1 translation: Ace == 14 */
	protected static int rank = 15;
	/** suites start at 0 */
	protected static int suite = 4;
	/** length depends on differentiation of table style (OFFENSIVE has 6 - max) */
	private int numCalls;
	/** length depends on differentiation of table style (OFFENSIVE has 4 - max) */
	private int numRaises;

	/** tables proposal */
	private int proposal;

	/**
	 * basic startinghandchart as int array </br>
	 * 1-4: card1Value,card1Color,card2Value.card2Color </br>
	 * 5: position (in classes: early,mid,late,sb,bb) </br>
	 * 6: how often was called in this round </br>
	 * 7: how often was raised in this round </br>
	 */
	public int[][][][][][][] table;


	/**
	 * Constructor table depending </br>
	 * table depending length - how much differentiation offers the table? </br>
	 * 	
	 * @param numPosition - usually and here: 5 standard position classes: early,mid,late,sb,bb 0-4
	 * @param numCalls - amount of previous calls by opponents
	 * @param numRaises - amount of previous calls by opponents
	 */
	public StartingHandChart(int numPosition, int numCalls, int numRaises) {

		/* table depending length */
		this.numCalls = numCalls;
		/** table depending length */
		this.numRaises = numRaises;

		/* init the table array */
		table = new int[rank][suite][rank][suite][numPosition][numCalls][numRaises];

		/* init the table with FOLD everywhere */
		initAllFold();
	}


	/* (non-Javadoc)
	 * @see bot.module.th.shc.IF_StartingHandChart#getProposal(game.model.Card[], int, int, int, int, int, int)
	 */
	public int[] getProposal(Card[] holeCards, int activePlayers, int smallBlind, int bigBlind, int position, int calls, int raises) {

		//		DebugOut.showVerboseShc("SHC: getProposal");

		int positionCat = getPositionCat(position, activePlayers);

		// read the table		
		int shcProp = lookInTable(holeCards, positionCat, calls, raises);
		DebugOut.showVerboseShc("__proposal: " + proposal);
		for (int i = 0; i < holeCards.length; i++) {
			DebugOut.showVerboseShc("holeCards: " + holeCards[i].toString());
		}
		DebugOut.showVerboseShc("activePlayers: " + activePlayers + ", position: " + position + ", calls: " + calls + ", raises: " + raises);

		int[] proposal = new int[2];
		// TODO Make it possible to raise(x) for SHC

		switch (shcProp) {
		case FOLD:
			proposal[0] = FOLD;
			break;

		case CHECK:
			proposal[0] = CHECK;
			break;

		case CALL:
			proposal[0] = CALL;
			break;

		case CALL20:
			proposal[0] = CALL20;
			break;

		case MINRAISE:
			proposal[0] = MINRAISE;
			break;

		case RAISE3:
			proposal[0] = MINRAISE;
			proposal[1] = bigBlind * (3 + activePlayers - 1);
			break;

		case RAISE4:
			proposal[0] = MINRAISE;
			proposal[1] = bigBlind * (4 + activePlayers - 1);
			break;

		case ALLIN:
			proposal[0] = ALLIN;
			break;

		default:
			System.err.println("StartingHandChart: getProposal: wrong value in switch case, got: " + shcProp);
			break;
		}

		return proposal;
	}


	/**
	 * maps the absolute position onto the 5 position categories</br>
	 * position categories: early,mid,late,sb,bb - positions start at 0</br>
	 * categories are filled from EARLY to LATE</br>
	 * e.g. 7 players:</br>
	 * 0->3(SB); 1->4(BB); 2->0(EARLY); 3->0(EARLY); 4->1(MIDDLE); 5->1(MIDDLE); 6->2(LATE);</br>
	 * @see util.poker.texas.PositionInt
	 * 
	 * @param position
	 * 			absolute position of the player in this hand</br>
	 * 			(0: first player behind the button; 1: second player behind the button; ...)
	 * @param activePlayers
	 * @return positionCategory
	 */
	private int getPositionCat(int position, int activePlayers) {

		if (position == 0) {
			return SB;
		}

		if (position == 1) {
			return BB;
		}

		int shcPosition = (position - 2 + activePlayers) % activePlayers;

		// 3 position categories
		int perCat = (activePlayers - 2) / 3;

		int remain = (activePlayers - 2) % 3;

		// add modulo to cat beginning at EARLY (to keep chart offensive)
		int catEarly = perCat;

		int catMiddle = perCat * 2;
		if (remain == 2) {
			catMiddle++;
		}

		if (shcPosition < catEarly) {

			return EARLY;
		}

		if (shcPosition < catMiddle) {

			return MIDDLE;
		}

		return LATE;
	}


	/**
	 * looks in the startinghandcharts table for its proposal
	 * 
	 * @param holeCards - own
	 * @param position as position class: early,mid,late,sb,bb - positions start at 1
	 * @param calls - how often was called in this round
	 * @param raises - how often was raised in this round
	 * @return proposal as int
	 */
	private int lookInTable(Card[] holeCards, int position, int calls, int raises) {

		/** shrink amount of calls and raises to tables length */
		int callsmod = calls;
		int raisesmod = raises;

		if (calls >= numCalls) {
			callsmod = numCalls - 1;
		}
		if (raises >= numRaises) {
			raisesmod = numRaises - 1;
		}

		int r1 = holeCards[0].getRank();
		int s1 = holeCards[0].getSuitAsInt();
		int r2 = holeCards[1].getRank();
		int s2 = holeCards[1].getSuitAsInt();

		//		DebugOut.showVerboseShc(r1 + "," + s1 + "," + r2 + "," + s2 + "," + position + "," + callsmod + "," + raisesmod + ",");

		proposal = table[r1][s1][r2][s2][position][callsmod][raisesmod];

		return proposal;
	}


	/** init the table with FOLD everywhere */
	private void initAllFold() {

		for (int r1 = 2; r1 < table.length; r1++) {
			for (int s1 = 0; s1 < table[0].length; s1++) {
				for (int r2 = 2; r2 < table[0][0].length; r2++) {
					for (int s2 = 0; s2 < table[0][0][0].length; s2++) {
						for (int p = 1; p < table[0][0][0][0].length; p++) {
							for (int c = 0; c < table[0][0][0][0][0].length; c++) {
								for (int r = 0; r < table[0][0][0][0][0][0].length; r++) {
									/* init FOLD */
									table[r1][s1][r2][s2][p][c][r] = FOLD;
								}
							}
						}
					}
				}
			}
		}
		/** init dead ranges of card1rank < 2 with -2 */
		for (int r1 = 0; r1 < 2; r1++) {
			for (int s1 = 0; s1 < table[0].length; s1++) {
				for (int r2 = 0; r2 < table[0][0].length; r2++) {
					for (int s2 = 0; s2 < table[0][0][0].length; s2++) {
						for (int p = 1; p < table[0][0][0][0].length; p++) {
							for (int c = 0; c < table[0][0][0][0][0].length; c++) {
								for (int r = 0; r < table[0][0][0][0][0][0].length; r++) {
									/* init NA */
									table[r1][s1][r2][s2][p][c][r] = NA;
								}
							}
						}
					}
				}
			}
		}
		/** init dead ranges of card2rank < 2 with -2 */
		for (int r1 = 0; r1 < table.length; r1++) {
			for (int s1 = 0; s1 < table[0].length; s1++) {
				for (int r2 = 0; r2 < 2; r2++) {
					for (int s2 = 0; s2 < table[0][0][0].length; s2++) {
						for (int p = 1; p < table[0][0][0][0].length; p++) {
							for (int c = 0; c < table[0][0][0][0][0].length; c++) {
								for (int r = 0; r < table[0][0][0][0][0][0].length; r++) {
									/* init NA */
									table[r1][s1][r2][s2][p][c][r] = NA;
								}
							}
						}
					}
				}
			}
		}
	}

}
